#include <pthread.h>
#include <iostream>
#include <string>
#include <queue>
const static int SIZE = 5;
template<class T>
class BlockQueue{
    private:
        bool Isfull(){
            return _block_queue.size() == _sum;
        }
        bool Isempty(){
            return _block_queue.empty();
        }
    public:
        BlockQueue(int sum = SIZE)
        :_sum(sum)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_p_cond, nullptr);
            pthread_cond_init(&_c_cond, nullptr);
        }
        void Pop(T* val){
            pthread_mutex_lock(&_mutex);
            while(Isempty())
            {
                pthread_cond_wait(&_c_cond, &_mutex);
            }
            *val = _block_queue.front();
            std::cout << "Pop" << std::endl;
            _block_queue.pop();
            pthread_mutex_unlock(&_mutex);
            pthread_cond_signal(&_p_cond);
        }
        void Equeue(const T& val){
            pthread_mutex_lock(&_mutex);
            while(Isfull())
            {
                pthread_cond_wait(&_p_cond, &_mutex);
            }
            std::cout << "Equeue" << std::endl;
            _block_queue.push(val);
            pthread_mutex_unlock(&_mutex);
            pthread_cond_signal(&_c_cond);
        }
        ~BlockQueue(){
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_p_cond);
            pthread_cond_destroy(&_c_cond);
        }
    private:
        std::queue<T> _block_queue;
        pthread_mutex_t _mutex;
        pthread_cond_t _p_cond;
        pthread_cond_t _c_cond;
        int _sum;
};